package com.monolithiot.camera.service;


import cn.hutool.json.JSONUtil;
import com.monolithiot.camera.GeneralResult;
import com.monolithiot.camera.help.CameraDataHelp;
import com.monolithiot.camera.pojo.CameraData;
import com.monolithiot.camera.pojo.CheckedPerson;
import com.monolithiot.camera.thread.ThreadPoolFactory;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static com.monolithiot.camera.help.CameraDataHelp.*;


/**
 * Create By TreeRoot
 * Create Time: 2024/02/06 03:16
 * Class Name: Tcp
 * Description:
 * 启动TCP客户端
 *
 * @author TreeRoot
 */
public class CameraClient {
    // 创建一个全局的线程池
    ExecutorService executorService = Executors.newFixedThreadPool(5, new ThreadPoolFactory("fixedThreadPool"));

    private int actionCount = 0;
    private long lastExecutedTime = System.currentTimeMillis();
    int totalBytesToRead = 64624;
    int bytesReadSoFar = 0;
    ByteBuffer receivedData = ByteBuffer.allocate(64624);
    final SocketServer socketServer;


    public CameraClient(SocketServer socketServer) {
        this.socketServer = socketServer;
    }


    /**
     * 1个字节（8位二进制数）可以表示为2个16进制字符
     *
     * @throws Exception 异常
     */
    public void client(InetSocketAddress inetSocketAddress) throws Exception {
        long lastReceiveTime = System.currentTimeMillis();
        SocketChannel socketChannel = SocketChannel.open(inetSocketAddress);
        Selector selector = Selector.open();
        socketChannel.configureBlocking(false);
        socketChannel.register(selector, SelectionKey.OP_READ);
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        // 接收服务端响应数据
        while (true) {
            if (selector.select() > 0) {
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectedKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    // 处理新接入的请求
                    if (key.isAcceptable()) {
                        ServerSocketChannel serverSocketChannelNew = (ServerSocketChannel) key.channel();
                        SocketChannel socketChannelNew = serverSocketChannelNew.accept();
                        socketChannelNew.configureBlocking(false);
                        socketChannelNew.register(selector, SelectionKey.OP_READ);
                    }
                    if (key.isReadable()) {
                        SocketChannel channel = (SocketChannel) key.channel();
                        int numRead = channel.read(buffer);
                        if (numRead == -1) {
                            channel.close();
                            key.cancel();
                            continue;
                        }
                        buffer.flip();
                        doReadByteData(buffer);
                        // 将未处理的数据移动到buffer的开始处
                        buffer.compact();
                        lastReceiveTime = System.currentTimeMillis(); // 更新最近接收数据的时间
                    }
                    iterator.remove();
                }
            }
            // 检查心跳超时
            long currentTime = System.currentTimeMillis();
            if (currentTime - lastReceiveTime > 500000) { // 超过5秒未收到数据
                socketChannel.close();
                selector.close();
                // 重新连接
                socketChannel = SocketChannel.open(inetSocketAddress);
                socketChannel.configureBlocking(false);
                socketChannel.register(selector, SelectionKey.OP_READ);
                lastReceiveTime = System.currentTimeMillis(); // 重置最近接收数据的时间
            }
        }

    }

    /**
     * 读取字节数据
     *
     * @param buffer byteBuffer数据集
     */
    private void doReadByteData(ByteBuffer buffer) {
        while (buffer.hasRemaining()) {
            int bytesRemaining = totalBytesToRead - bytesReadSoFar;
            int bytesToRead = Math.min(buffer.remaining(), bytesRemaining);
            for (int i = 0; i < bytesToRead; i++) {
                receivedData.put(buffer.get());
                bytesReadSoFar++;
            }
            if (bytesReadSoFar == totalBytesToRead) {
                //校验数据包是否非法
                if (checkDataPacketIsIllegal(receivedData.array())) {
                    System.out.println("数据包非法，丢弃数据包");
                    bytesReadSoFar = 0;
                    receivedData.clear();
                    continue;
                }
                doOtherAction(receivedData);
                bytesReadSoFar = 0;
                receivedData.clear();
            }
        }
    }


    /**
     * 其他操作
     *
     * @param receivedData 接收到的数据
     */
    private void doOtherAction(ByteBuffer receivedData) {
        if (actionCount >= 10) {
            actionCount = 0;
        }
        long currentTime = System.currentTimeMillis();
        if (currentTime - lastExecutedTime >= 100 && actionCount < 10) {
            CameraData cameraData = new CameraData();
            List<CheckedPerson> checkedPersonList = new ArrayList<>();
            // 相机左边相机的图像数据
            byte[] bytes = new byte[320 * 180];
            System.arraycopy(receivedData.array(), 4, bytes, 0, bytes.length);
//            try {
//                BufferedImage image = CameraDataHelp.createImage(0, 0, bytes);
//                String base64Image = convertImageToBase64(image);
//                //写入到本地
//                ImageIO.write(image, "jpg", new File("C:\\Users\\treeroot\\Desktop\\img\\"+1+".jpg"));
//            } catch (Exception ignored) {
//                // 处理异常
//            }
            cameraData.setImageDataByte(bytes);
            cameraData.setMaxDetectionAreaLeftTopX(getMaxDetectionAreaLeftTopX(receivedData));
            cameraData.setMaxDetectionAreaLeftTopY(getMaxDetectionAreaLeftTopY(receivedData));
            cameraData.setMaxDetectionAreaRightBottomX(getMaxDetectionAreaRightBottomX(receivedData));
            cameraData.setMaxDetectionAreaRightBottomY(getMaxDetectionAreaRightBottomY(receivedData));

            cameraData.setMinDetectionAreaHeight(getMinDetectionAreaWidth(receivedData));
            cameraData.setMinDetectionAreaWidth(getMinDetectionAreaWidth(receivedData));



            cameraData.setCurrentHeadDetectionAreaLeftTopX(getCurrentHeadDetectionAreaLeftTopX(receivedData));
            cameraData.setCurrentHeadDetectionAreaLeftTopY(getCurrentHeadDetectionAreaLeftTopY(receivedData));
            cameraData.setCurrentHeadDetectionAreaRightBottomX(getCurrentHeadDetectionAreaRightBottomX(receivedData));
            cameraData.setCurrentHeadDetectionAreaRightBottomY(getCurrentHeadDetectionAreaRightBottomY(receivedData));

            cameraData.setDetectionLinePosition(getDetectionLinePosition(receivedData));
            cameraData.setHeadDetectionLinePosition(getHeadDetectionLinePosition(receivedData));

            cameraData.setMaxDetectionAreaLeftBottomX(getMaxDetectionAreaLeftBottomX(receivedData));
            cameraData.setMaxDetectionAreaLeftBottomY(getMaxDetectionAreaLeftBottomY(receivedData));
            cameraData.setMaxDetectionAreaRightTopX(getMaxDetectionAreaRightTopX(receivedData));
            cameraData.setMaxDetectionAreaRightTopY(getMaxDetectionAreaRightTopY(receivedData));

            //当前检测区域
            cameraData.setCurrentDetectionAreaLeftBottomX(getCurrentDetectionAreaLeftBottomX(receivedData) / 2);
            cameraData.setCurrentDetectionAreaLeftBottomY(getCurrentDetectionAreaLeftBottomY(receivedData) / 2);
            cameraData.setCurrentDetectionAreaRightTopX(getCurrentDetectionAreaRightTopX(receivedData) / 2);
            cameraData.setCurrentDetectionAreaRightTopY(getCurrentDetectionAreaRightTopY(receivedData) / 2);
            cameraData.setCurrentDetectionAreaLeftTopX(getCurrentDetectionAreaLeftTopX(receivedData)/2);
            cameraData.setCurrentDetectionAreaLeftTopY(getCurrentDetectionAreaLeftTopY(receivedData)/2);
            cameraData.setCurrentDetectionAreaRightBottomX(getCurrentDetectionAreaRightBottomX(receivedData)/2);
            cameraData.setCurrentDetectionAreaRightBottomY(getCurrentDetectionAreaRightBottomY(receivedData)/2);

            cameraData.setCurrentHeadDetectionAreaLeftBottomX(getCurrentHeadDetectionAreaLeftBottomX(receivedData));
            cameraData.setCurrentHeadDetectionAreaLeftBottomY(getCurrentHeadDetectionAreaLeftBottomY(receivedData));
            cameraData.setCurrentHeadDetectionAreaRightTopX(getCurrentHeadDetectionAreaRightTopX(receivedData));
            cameraData.setCurrentHeadDetectionAreaRightTopY(getCurrentHeadDetectionAreaRightTopY(receivedData));
            int checkedPeopleNum = CameraDataHelp.getCheckPeopleNum(receivedData);
//            if (checkedPeopleNum > 0) {
//                System.out.println("检测到了" + checkedPeopleNum + "人" + new Date());
//            } else System.out.println("无人经过");
            for (int i = 0; i < checkedPeopleNum; i++) {
                CheckedPerson checkedPerson = new CheckedPerson();
                checkedPerson.setHeadNum(CameraDataHelp.getHeadNums(receivedData, i));
                checkedPerson.setHeadX(getHeadX(receivedData, i) / 2);
                checkedPerson.setHeadY(CameraDataHelp.getHeadY(receivedData, i) / 2);
                checkedPerson.setHeight(CameraDataHelp.getHeight(receivedData, i));
                checkedPerson.setTrackStatus(CameraDataHelp.getTrackStatus(receivedData, i));
                int stayTime = getStayTime(receivedData, i);
                checkedPerson.setStayTime(stayTime);
//                System.out.println("人头坐标" + checkedPerson.getHeadX()
//                        + "," + checkedPerson.getHeadY()
//                        + "编号" + checkedPerson.getHeadNum()
//                        + "停留时间"+stayTime);
                checkedPersonList.add(checkedPerson);
            }

            cameraData.setCheckedPeople(checkedPersonList);
            lastExecutedTime = currentTime;
            executorService.submit(() -> {
                try {
                    actionCount++;
                    socketServer.broadcast(JSONUtil.toJsonStr(GeneralResult.ok(cameraData)));
                } catch (Exception e) {
                    System.out.println("遇到异常："+e.getMessage());
                }
            });
        }
    }
}
